package com.managertrade.util.strategy;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Random;

public class FundsWindowBacktest {

    // 中间区间比例参数（越小越灵敏）
    private static final BigDecimal ALPHA = new BigDecimal("0.05");

    /**
     * 回测方法
     * @param fundsList 资金曲线（List<BigDecimal>）
     * @param windowSize 窗口长度（例如 30）
     * @return Result（包含收益率与信号准确率）
     */
    public static Result backtest(List<BigDecimal> fundsList, int windowSize,BigDecimal ALPHA) {
        int correct = 0, total = 0;
        BigDecimal fundsValue = BigDecimal.valueOf(10000); // 初始资金

        for (int i = windowSize; i < fundsList.size() - 1; i++) {
            // 取最近 N 条数据
            List<BigDecimal> window = fundsList.subList(i - windowSize, i);
            BigDecimal current = fundsList.get(i);
            String signal = getSignal(window, current,ALPHA);

            BigDecimal next = fundsList.get(i + 1);
            BigDecimal diff = next.subtract(current);

            // 根据信号更新资金
            if (signal.equals("long")) {
                fundsValue = fundsValue.add(diff);
                total++;
                if (diff.compareTo(BigDecimal.ZERO) > 0) correct++;
            } else if (signal.equals("short")) {
                fundsValue = fundsValue.subtract(diff);
                total++;
                if (diff.compareTo(BigDecimal.ZERO) < 0) correct++;
            }
        }

        double returnPct = fundsValue.subtract(BigDecimal.valueOf(10000))
                .divide(BigDecimal.valueOf(10000), 4, BigDecimal.ROUND_HALF_UP)
                .multiply(BigDecimal.valueOf(100))
                .doubleValue();

        double accuracy = total == 0 ? 0 : (correct * 100.0 / total);
        return new Result(returnPct, accuracy);
    }
    /**
     * 回测资金趋势策略
     * @param fundsList 资金数据序列
     * @param thresholdPct 涨跌触发阈值百分比，比如 0.001 = 0.1%
     * @param positionRatio 每次交易资金比例，比如 0.5 = 50%
     * @param accumulationCount 连续趋势累积根数，比如 3
     */
    public static Result backtest2(List<BigDecimal> fundsList, double thresholdPct,
                                   double positionRatio, int accumulationCount) {

        if (fundsList == null || fundsList.size() < 4) {
            return new Result(0, 0);
        }

        BigDecimal fundsValue = BigDecimal.valueOf(5); // 初始资金
        int correct = 0, total = 0;

        int currentDirection = 0; // 0=未定, 1=long, -1=short
        int trendCount = 0;

        // ====================================
        // ① 自适应手续费（学习平均波动）
        // ====================================
        BigDecimal avgChange = BigDecimal.ZERO;
        for (int i = 1; i < fundsList.size(); i++) {
            avgChange = avgChange.add(fundsList.get(i).subtract(fundsList.get(i - 1)).abs());
        }
        avgChange = avgChange.divide(BigDecimal.valueOf(fundsList.size() - 1), 8, RoundingMode.HALF_UP);

        // 动态手续费门槛
        BigDecimal feeThresholdDynamic = avgChange.multiply(BigDecimal.valueOf(0.8));
        if (feeThresholdDynamic.compareTo(BigDecimal.ZERO) <= 0) {
            feeThresholdDynamic = BigDecimal.valueOf(0.00001);
        }

        // 动态阈值：波动越大，阈值越高
        BigDecimal dynamicThreshold = avgChange.multiply(BigDecimal.valueOf(1.5));

        BigDecimal lastDiff = BigDecimal.ZERO;
        int smallMoveCount = 0;

        // ====================================
        // ② 主循环：趋势检测 + 资金变化
        // ====================================
        for (int i = 1; i < fundsList.size(); i++) {

            BigDecimal prev = fundsList.get(i - 1);
            BigDecimal curr = fundsList.get(i);
            BigDecimal diff = curr.subtract(prev);

            // 固定阈值 + 动态阈值取较大者
            BigDecimal fixedThreshold = prev.multiply(BigDecimal.valueOf(thresholdPct));
            BigDecimal threshold = fixedThreshold.max(dynamicThreshold);

            // 噪音过滤：变化小于手续费，认为无效
            if (diff.abs().compareTo(feeThresholdDynamic) < 0) {
                smallMoveCount++;
            }

            // 加速度（趋势强化）
            boolean acceleratingUp = diff.compareTo(lastDiff) > 0 && diff.compareTo(BigDecimal.ZERO) > 0;
            boolean acceleratingDown = diff.compareTo(lastDiff) < 0 && diff.compareTo(BigDecimal.ZERO) < 0;

            boolean isUp = (diff.compareTo(threshold) > 0) || acceleratingUp;
            boolean isDown = (diff.compareTo(threshold.negate()) < 0) || acceleratingDown;

            // 趋势累积逻辑
            if (isUp) trendCount = Math.min(trendCount + 1, accumulationCount * 3);
            else if (isDown) trendCount = Math.max(trendCount - 1, -accumulationCount * 3);
            else trendCount = (int) (trendCount * 0.7); // 缓慢衰减，抗震荡

            // 达到趋势阈值才确定方向
            if (trendCount >= accumulationCount) currentDirection = 1;
            else if (trendCount <= -accumulationCount) currentDirection = -1;

            // 执行交易（资金变化模拟）
            BigDecimal position = diff.multiply(BigDecimal.valueOf(positionRatio));
            if (currentDirection == 1) { // 做多
                fundsValue = fundsValue.add(position);
                total++;
                if (diff.compareTo(BigDecimal.ZERO) > 0) correct++;
            } else if (currentDirection == -1) { // 做空
                fundsValue = fundsValue.subtract(position);
                total++;
                if (diff.compareTo(BigDecimal.ZERO) < 0) correct++;
            }

            lastDiff = diff;
        }

        // ====================================
        // ③ 判断震荡比例：横盘多则 HOLD
        // ====================================
        double smallMoveRatio = (double) smallMoveCount / (fundsList.size() - 1);
        double holdThreshold = 0.45 + 0.15 * (fundsList.size() / 25.0);
        if (smallMoveRatio > holdThreshold) {
            // 横盘期不操作 → 减少资金磨损
            return new Result(0, 50); // 模拟不交易（持币观望）
        }

        // ====================================
        // ④ 计算回测结果
        // ====================================
        double returnPct = fundsValue.subtract(BigDecimal.valueOf(5))
                .divide(BigDecimal.valueOf(5), 4, RoundingMode.HALF_UP)
                .multiply(BigDecimal.valueOf(100))
                .doubleValue();

        double accuracy = total == 0 ? 0 : (correct * 100.0 / total);

        return new Result(returnPct, accuracy);
    }

    /**
     * 根据最近窗口区间计算信号
     */
    public static String getSignal(List<BigDecimal> window, BigDecimal current,BigDecimal ALPHA) {
        BigDecimal max = window.stream().max(BigDecimal::compareTo).get();
        BigDecimal min = window.stream().min(BigDecimal::compareTo).get();
        BigDecimal mid = max.add(min).divide(BigDecimal.valueOf(2), BigDecimal.ROUND_HALF_UP);

        BigDecimal range = max.subtract(min);
        BigDecimal upperBand = mid.add(range.multiply(ALPHA));
        BigDecimal lowerBand = mid.subtract(range.multiply(ALPHA));

        if (current.compareTo(max) > 0) {
            return "long";
        } else if (current.compareTo(min) < 0) {
            return "short";
        } else if (current.compareTo(upperBand) > 0) {
            return "long";
        } else if (current.compareTo(lowerBand) < 0) {
            return "short";
        } else {
            return "观望";
        }
    }

    /**
     * 结果封装类
     */
    public static class Result {
        public double totalReturn; // 收益率
        public double accuracy;    // 信号准确率

        public Result(double totalReturn, double accuracy) {
            this.totalReturn = totalReturn;
            this.accuracy = accuracy;
        }
    }
}

